package org.micro.rbac.core.config;

import com.alibaba.fastjson2.support.spring6.http.converter.FastJsonHttpMessageConverter;
import com.google.common.collect.Lists;
import jakarta.validation.Validator;
import lombok.extern.slf4j.Slf4j;
import org.micro.rbac.core.annotation.Intercept;
import org.micro.rbac.core.interceptor.AbstractHandlerInterceptor;
import org.micro.rbac.util.FastJsonUtil;
import org.micro.rbac.util.ValidUtil;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * webMVC 配置
 *
 * @author hongsir
 * @since 2023-03-28 20:45
 **/
@Slf4j
@Configuration
public class MyWebConfig implements WebMvcConfigurer, InitializingBean, ApplicationContextAware {

    /**
     * 拦截器排序最小个数
     */
    private final static int MIN_SORT_SIZE = 2;
    private ApplicationContext applicationContext;
    private final List<AbstractHandlerInterceptor> interceptors = Lists.newArrayList();

    /**
     * 设置上下文
     *
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 注入拦截器
     */
    @Override
    public void afterPropertiesSet() {
        Map<String, AbstractHandlerInterceptor> interceptorMap = this.applicationContext.getBeansOfType(AbstractHandlerInterceptor.class);
        for (Map.Entry<String, AbstractHandlerInterceptor> entry : interceptorMap.entrySet()) {
            interceptors.add(entry.getValue());
        }
        log.info("需要加载的拦截器个数：{}", interceptors.size());
    }

    /**
     * 设置拦截器
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //根据优先级进行排序
        if (interceptors.size() >= MIN_SORT_SIZE) {
            interceptors.sort(Comparator.comparingInt(o -> o.getClass().getAnnotation(Intercept.class).priority()));
        }
        for (AbstractHandlerInterceptor interceptor : interceptors) {
            Intercept webInterceptorUrl = interceptor.getClass().getAnnotation(Intercept.class);
            registry.addInterceptor(interceptor).addPathPatterns(webInterceptorUrl.include()).excludePathPatterns(webInterceptorUrl.exclude());
        }
    }

    /**
     * 配置请求参数校验组件
     *
     * @return
     */
    @Bean
    @Primary
    public Validator validator() {
        return ValidUtil.getValidator();
    }

    /**
     * 使用 FastJsonHttpMessageConverter 来替换 Spring MVC 默认的 HttpMessageConverter
     * 以提高 @RestController @ResponseBody @RequestBody 注解的 JSON序列化和反序列化速度。
     **/
    @Override
    @Primary
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 添加fastjson转换器
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        // 添加支持的媒体类型
        List<MediaType> supportedMediaTypes = new ArrayList<>();
        supportedMediaTypes.add(MediaType.ALL);
        // 将convert添加到converters
        converter.setFastJsonConfig(FastJsonUtil.config());
        converter.setSupportedMediaTypes(supportedMediaTypes);
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        converters.add(0, converter);
    }
}
